iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
2
Modern Web

勇者鬥Vue龍系列 第 7

Vue.js Core 30天屠龍記(第7天): 計算屬性

  • 分享至 

  • xImage
  •  

在模板中可以放入 JavaScript 表達式來做運算,在簡單的例子中很方便,但在真正開發時,會造成兩個問題:

  • 在模板內寫表達式,會看到 HTML 內穿插著 JavaScript 的代碼,在可讀性上大打折扣。
  • 如果單純用表達式的話,如果有復用的需求會造成在模板上重複寫多次相同的邏輯,降低可維護性。

今天介紹的計算屬性可以解決這些煩惱。

將模板內的表達式用計算屬性改寫

現在我們有下面這樣的代碼:

var vm = new Vue({
  el: '#app',
  data: {
    number: 1
  }
});
<div id="app">
  <button @click="number++">+</button>
  <button @click="number--">-</button>
  <div>
    <span>Number {{number}} is {{number % 2 === 0 ? 'even' : 'odd'}}</span>
  </div>
</div>

{{number % 2 === 0 ? 'even' : 'odd'}} 會判斷 number 是否是偶數,如果是的話輸出 even ,否的話則輸出 odd ,現在我們將它用 computed 改寫:

var vm = new Vue({
  el: '#app',
  data: {
    number: 1
  },
  computed: {
    numberEvenOrOdd() {
      return this.number % 2 === 0 ? 'even' : 'odd';
    }
  }
});
<div id="app">
  <button @click="number++">+</button>
  <button @click="number--">-</button>
  <div>
    <span>Number {{number}} is {{numberEvenOrOdd}}</span>
  </div>
</div>

這個例子說明了計算屬性的幾個特性:

  • 在選項物件中以 computed 屬性設置。
  • 每個對應的計算屬性都是一個具有回傳值且沒有傳入參數的 Function 。
  • 在計算屬性的 Function 中的 this 會指向 Vue 實體,因此如果要使用 this 的話,則不能使用此種寫法 。
  • 在模板中直接以 Function 名稱設置,不用加 ()
  • 可以從 Mustache 標籤中的引用方式得知,計算屬性跟一般的資料屬性一樣放於 Vue 實體中。

使用 numberEvenOrOdd 替代掉原本的表達式後,整個模板變得更加易讀,如果要在頁面上多個地方做設置,也只要重複使用 numberEvenOrOdd 變數就好了。

其實計算屬性可以用 arrow function 撰寫,下面會有詳細說明。

計算屬性特性說明

會跟著來源資料變化

一旦在 computed function 中參考到的資料有變化, 計算屬性就會跟著變化。

像是上節的例子,當 number 屬性變化時, numberEvenOrOdd 的值會在 evenodd 間跳動。

依然可以使用 arrow function

上面有說到如果要使用 this 的話,則不能使用此種寫法 ,但其實 Vue 有提供計算屬性 arrow function 的寫法:

var vm = new Vue({
  ...
  computed: {
    ...
    numberEvenOrOddArrow: vm => vm.number % 2 === 0 ? 'even' : 'odd'
  }
});

計算屬性的函數會傳入一個 vm 的參數,這個參數會是 Vue 的實體,也就是原本使用的 this ,因此可以使用 arrow function 寫計算屬性的代碼。

計算屬性也有 Setter

在前面的例子中計算屬性是一個 Function ,這個 Function 其實就是這個計算屬性的 Getter ,所以這樣的宣告方式只會有 Getter 可以配置,但 Vue 有提供計算屬性 Setter 的設置方式。

var vm = new Vue({
  ...
  computed: {
    ...
    numberEvenOrOddSetter: {
      get() {
        return this.number % 2 === 0 ? 'even' : 'odd';
      },
      set(evenOrOdd) {
        if(this.number % 2 === 0){
          if(evenOrOdd !== 'even') this.number++;
          return;
        }
        if(evenOrOdd !== 'odd') this.number++;
      }
    }
  },
});
<div id="app">
  ...
  <div>
    <span>Number {{number}} is {{numberEvenOrOddSetter}}</span>
    <button @click="numberEvenOrOddSetter='even'">Set Even</button>
    <button @click="numberEvenOrOddSetter='odd'">Set Odd</button>
  </div>
</div>

當按下 Set Even/Set Odd 時,如果 number 不是 Even/Odd ,則 number 會加一。

跟 mehods 的比較

其實計算屬性可以做的,方法也一樣可以做到,以上面的例子來說:

var vm = new Vue({
  ...
  methods: {
    evenOrOdd(){
      return this.number % 2 === 0 ? 'even' : 'odd';
    }
  }
});
<div id="app">
  ...
  <div>
    <span>Number {{number}} is {{evenOrOdd()}}</span>
  </div>
</div>

在模板上用 evenOrOdd() 執行方法後取回結果,跟計算屬性得到的值是相同的。

既然這樣為什麼還需要計算屬性呢? 在上節說明特性的第一點有提到計算屬性會跟著來源資料變化,其實更精確地說是會跟著來源資料變化,看了下面的例子應該就了解了:

var vm = new Vue({
  ...
  computed: {
    ...
    datePlusNumberComputed() {
      return Date.now();
    }
  },
  methods: {
    ...
    datePlusNumberMethod() {
      return Date.now();
    }
  }
});
<div id="app">
  ...
  <div>
    <div>Computed: {{datePlusNumberComputed}}</div>
    <div>Method: {{datePlusNumberMethod()}}</div>
  </div>
</div>

https://ithelp.ithome.com.tw/upload/images/20181022/20107789YHl3V32gUY.png

可以看到 datePlusNumberComputed 因為在按了按鈕後並沒有任何跟此計算屬性有關的資料來源改變,所以它不會執行 Function 。

方法就不同了,只要每次重新渲染畫面就會執行一次。

如果這個回傳值跟資料來源的變化有關,那應該在來源有變化時在執行即可,否則會產生不必要的運算時間,降低效能,所以當要取得某個結果跟其他資料有關的值的話,用計算屬性才是上策。

Demo

小結

本文一開始介紹了計算屬性使用的方法,在 Vue 實體中以 computed 設置計算屬性,於模板上就可以像一般的資料屬性一樣做使用。

之後說明了計算屬性會跟著來源資料變化可以使用 arrow function 以及擁有 Setter 的特性。

最後與 methods 做比較,得出如果想取得結果與某資料屬性有關則使用計算屬性的比較結果。

參考資料


上一篇
Vue.js Core 30天屠龍記(第6天): 模板語法 Part 2 - Directives
下一篇
Vue.js Core 30天屠龍記(第8天): 監聽器( watch )
系列文
勇者鬥Vue龍32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言